var mwg = null; // the MindWave Graph JIT object (SpaceTree or whatever)

/** 
 * CONSTANTS
 */
var KEY_GRAPH = 'mwg',
KEY_TEST = 'TESTY',
KEY_DIRTY = 'graph changed',
K_ST_INIT = 'state init load',
K_NUM_ACTIVE = 'num active viewers';

var SEP = '_';
 
var NEWROOT = '.r_',
 ADDCHILD = '.c_',
 LEN_CMD = 3;

var NID_PREFIX = 'n_';

/** 
 * Initialization
 */
function init() {
	conlog("MindWave Startup.");
	conlog("STARTUP STATE: ");
	printState(); // getViewer may be null due to participants add comes later
	conlog("Initializing graph and registering state update handler.");	
	initializeGraph();
	initializeStateHandling();
}

function deinit() {
	conlog("MindWave Shutdown.");
	
	if (wave.getState()) {
		var numActive = wave.getState().get(K_NUM_ACTIVE);	
		//submitUpdate(K_ST_INIT, null, "CLEAR STATE INIT FLAG FOR NOW"); // TODO IMPORTANT
		// TODO finish deinit
		//conlog("Removing flag signalling the initial state load.");
		//submitUpdate(K_ST_INIT, null); // TODO IMPORTANT only do this for last participant using this gadget
		//conlog("Saving special graph state info.");
		//saveGraph();
	}
}

function initializeStateHandling() {
	if (wave && wave.isInWaveContainer()) {
		wave.setStateCallback(stateUpdated);
	}
}

function initializeGraph() {
	var graphdiv = document.getElementById('graph');
	var w = 800, h = 600; // TODO div.offsetwidth?
	var canvas = new Canvas('mycanvas', {
		'injectInto': 'graph',
		'width': w,
		'height': h,
		'backgroundColor': '#ffffff'
	});

	var graphConfig = {
		duration: 400,         //set duration for the animation
		transition: Trans.Quart.easeInOut,         //set animation transition type
		levelDistance: 50,         //set distance between node and its children
		Node: {
			height: 60,
			width: 150,
			type: 'rectangle',
			color: '#ccc',
			overridable: true
		},
		Edge: {
			type: 'bezier',
			overridable: true
		},
		onCreateLabel: function(label, node){  
         label.id = node.id;              
         label.innerHTML = node.name;  
         label.onclick = labelClick; // TODO use this instead of new function for every node
         //set label styles  
         var style = label.style;  
         style.width = 150 + 'px';         
         style.cursor = 'pointer';  
         style.color = '#000';  
         style.fontSize = '0.8em';  
         style.textAlign= 'center';
         style.fontFamily = "Arial";
         style.padding = "3px";
     }
	};

	mwg = new ST(canvas, graphConfig);
}

/**
 * Loads GRAPH into display.
 * mwg must have already been initialized.
 * 
 * GRAPH - an object with JIT "JSON" tree (or graph) format
 */
function loadGraph(graph) {
	mwg.loadJSON(graph); // FYI JIT doesn't like empty graphs {} for some functions so save graph should not save such
	mwg.compute();     //compute node positions and layout
	mwg.onClick(mwg.root);     //emulate a click on the root node // TODO any issue with empty graph?	
}

// TODO possible to save graph only just before gadget unload? window unload might lose access to state first?
// FIXME LATER deinit on unload may be causing trouble during gadget deletion
function saveGraph() {
	if (mwg && mwg.root && wave.getState()) { // REQUIRES 1) graph with root 2) root must not be false in logical context
		var gstring = gadgets.json.stringify(mwg.json);
		conlog("***** DELTA: Saving graph. Graph: " + gstring);
		submitUpdate(KEY_GRAPH, gstring);
	} else if (wave.getState()) {
		conlog("***** DELTA: There is no graph to save. Clearing previous saved graph (if exists).");
		submitUpdate(KEY_GRAPH, null); // ensures clear memory of any initial graph
	} else {
		conlog("No gadget state available and no graph to save.");
	}
	return true;
}

/**
 * Event and delta management
 */
function submitUpdate(key, value, msg) {
	if (msg) {
		conlog("***** DELTA: " + msg);
	}
	var d = {};
	d[key] = value;
	wave.getState().submitDelta(d);
}

function stateUpdated() {
	conlog("State callback triggered ***********");
	printState();
	conlog("***** DELTA: Removing test item (if exists): " + KEY_TEST);
	submitUpdate(KEY_TEST, null);

	var state = wave.getState();
	var isStateInit = !state.get(K_ST_INIT);
	isStateInit = true; // TODO for testing
	// load graph from previous state if this is first person to open the gadget
	if (isStateInit && state.get(KEY_GRAPH)) {
		var gstring = state.get(KEY_GRAPH);
		var graph = gadgets.json.parse(gstring);
		conlog("Loading graph: " + ostring(graph) + " from JSON: " + gstring);
		loadGraph(graph);
		submitUpdate(K_ST_INIT, 'done', "Note that state has been init by someone.");
	} else if (isStateInit) {
		conlog("NEW GADGET. There is no previous graph.");
		conlog("Test loadGraph using canned tree ******************") // TODO testing
		loadGraph(testTree);
		submitUpdate(K_ST_INIT, 'done', "Note that state has been init by someone.");
	} else {
		conlog("Someone opened gadget recently. Skipping load from previous save.");
	}
	
	// TODO add child and save graph, add root node and save, etc
	var keys = state.getKeys();
	for (var i=0; i<keys.length; i++) { // TODO make cmd queue instead?
		var key = keys[i];
		var cmd = key.substring(0, LEN_CMD);
		var value = state.get(key);
		switch (cmd) {
			case ADDCHILD:
				conlog("TODO REALLY ADD CHILD: " + value);
				var data = gadgets.json.parse(value);
				var nstr = data.n;
				//mwg.addSubtree(, 'animate'
				conlog("Parent id : " + data.pn + " new child data: " + nstr);
				var parent = mwg.graph.getNode(data.pn);
				console.log("got parent? " + parent.name);
				var nodeJson = gadgets.json.parse(nstr);
				var node = new Graph.Node(nodeJson); // todo complex
				//parent.addAdjacency(node, {});
				mwg.addSubtree(nodeJson, 'animate'); ///test
				console.log("ok?");
				//st.onClick(parent.id); // TODO necessary?
			
				
				saveGraph();
				submitUpdate(key, null, "Done adding child. Remove command."); // Remove cmd
				break;
		}
	}
		
	if (wave.getState().get(KEY_DIRTY)) { // TODO can remove this is save with every change
		saveGraph(); // TODO see how saving with every update effects performance (there may be trouble with saving on unload)
		submitUpdate(KEY_DIRTY, null); // let's see OT magic handle changes during save process
	}
}

function labelClick(event) {
	var parentId = event.target.id;
	conlog("Label clicked. Node Id: " + parentId); // TODO work with jeff
	// event.target is like <div id="a" class="node" style="padding: 3px; position: absolute; width: 150px; cursor: pointer; color: rgb(0, 0, 0); font-size: 0.8em; text-align: center; font-family: Arial; left: 325px; top: 270px;">
	addChildDelta('Test NODE LABEL click on ' + parentId, parentId);
}

function addChildButtonClick(parentId) {
	addChildDelta('Test BUTTON click on ' + parentId, parentId);
}

/**
 * Graph data management
 */
function addChildDelta(text, parentId) {
	conlog("*********** GRAPHCHANGING EVENT: ADDING CHILD ***********");
	var msg = makeNodeMessage(text, parentId);
	conlog("TODO Adding child to parent: " + msg);
	var key = ADDCHILD + msg.n.id;
	submitUpdate(key, gadgets.json.stringify(msg));
}

function makeNodeMessage(text, parentId) {
	var msg = {'pn': parentId, 'n': ""};
	var n = {};
	n.id = 'TODOuniqID!'; // TODO IMPORTANT
	n.name = text; // node name is the label text
	n.children = [];
	var data = {};
	if (wave.getViewer()) {
		var p = wave.getViewer();
		//data.vid = p.getId();
		data.vname = p.getDisplayName();
		//data.vimg = getThumbnailUrl(); // TODO put this in later
	}
	n.data = data;
	msg.n = gadgets.json.stringify(n); // TODO ok for now.
	return msg;
}

/**
 * 
 */

gadgets.util.registerOnLoadHandler(init); //window.addEventListener("load", init, false);
window.addEventListener("unload", deinit, true); // usecapture==true to get in early

/***************
 * DEBUGGING AND UTILITY
 * TODO remove some of this debugging and utility stuff
 *
 */
 
var debug = true;

function conlog(msg) {
	if (debug) {
		console.log(msg);
	}
}

function printState() {
	if (debug) {
		console.log("GADGET ENV AND STATE -------------------------");
		if (wave.getViewer()) {
			console.log("  Viewer: " + wave.getViewer().getDisplayName() + " ID:" + wave.getViewer().getId());
		} else {
			console.log("Viewer load is incomplete. (You're not a participant yet!)");
		}
		if (wave.getState()) {
			console.log("  Gadget State: ");
			console.log("  " + wave.getState().toString());	
		} else {
			console.log("  There is no Gadget State.");
		}
	}
}

function ostring(a) { // FEH what's the one-liner for this?
	var s = "";
	for (var x in a) {
	    s += x + ": " + a[x] + ", ";
	}
	return s;
}

 /// DEBUG: Quickies
function onclickTestDelta() {
	conlog("TEST DELTA BUTTON CLICKED.");
	conlog("Submitting test delta...");
	submitUpdate(KEY_TEST, 'testy');
	conlog("...Delta submitted.");
}

function onclickGetSetDelta() { // TODO remove this debugging callback
	conlog("testButtonClicked(): submitting a simple delta");
	var value = parseInt(wave.getState().get('count', '0'));
	wave.getState().submitDelta({
		'count': value + 1
		});
}

var testTree = {
	id: "a",
	name: "Node A",
	data: {},
	children: [	{
		id: "b",
		name: "Node B",
		data: {},
		children: []
	},
	{
		id: "c",
		name: "Lorem ipsum dolor sit amet. Sic laren puir necesitat guerdo.",
		data: {},
		children: [	{
			id: "d",
			name: "Node D",
			data: {},
			children: []
		}
		]
	}
	]
};
